/*************** YOU SHOULD NOT MODIFY ANYTHING IN THIS FILE ***************/

#define _GNU_SOURCE
#include <stdio.h>
#undef _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "testrunner.h"
#include "mp2_tests.h"

#define quit_if(cond) do {if (cond) exit(EXIT_FAILURE);} while(0)

/* Prepare input, reroute file descriptors, and run the program. */
void run_test(const char *input, int argc, char **argv)
{
	/* Prepare input */
	FILE *in = fopen("mp2.in", "w");
	fprintf(in, input);
	fclose(in);
	/* Reroute standard file descriptors */
	freopen("mp2.in",  "r", stdin );
	freopen("mp2.out", "w", stdout);
	freopen("mp2.err", "w", stderr);
	/* Run the program */
	quit_if(main(argc, argv) != EXIT_SUCCESS);
	fclose(stdout);
	fclose(stderr);
}

/* P5.1: Test of executing commands in the path */
int test_path(int argc, char **argv)
{
	char *args[] = { "./shell", NULL };
	FILE *out, *err;
	int pid_tmp;

	/* Run the test */
	run_test("ls\n/bin/ls\nexit\n", 1, args);
	/* Check output */
	err = fopen("mp2.err", "r");
	quit_if(fscanf(err, "  Parent says 'child process has been forked with pid=%d'\n"
	                    "  Parent says 'wait() returned so the child with pid=%d is finished.'\n"
	                    "  Parent says 'child process has been forked with pid=%d'\n"
	                    "  Parent says 'wait() returned so the child with pid=%d is finished.'\n",
	               &pid_tmp, &pid_tmp, &pid_tmp, &pid_tmp) != 4);
	quit_if(!feof(err));
	fclose(err);
	return EXIT_SUCCESS;
}

/* P5.2: Test of command line counter */
int test_counter(int argc, char **argv)
{
	char *args[] = { "./shell", NULL };
	FILE *out, *err;
	int pid_tmp;

	/* Run the test */
	run_test("\n/bin/true\nexit\n", 1, args);
	/* Check output */
	out = fopen("mp2.out", "r");
	quit_if(fscanf(out, "Shell(pid=%d)1} Shell(pid=%d)1} Shell(pid=%d)2} Exiting process %d\n", &pid_tmp, &pid_tmp, &pid_tmp, &pid_tmp) != 4);
	quit_if(!feof(out));
	fclose(out);
	return EXIT_SUCCESS;
}

/* P5.3: Test of re-executing earlier commands */
int test_rerun(int argc, char **argv)
{
	char *args[] = { "./shell", NULL };
	FILE *out, *err;
	int pid_tmp;

	/* Run the test */
	run_test("/bin/echo test\n!1\n!4\nexit\n", 1, args);
	/* Check output */
	out = fopen("mp2.out", "r");
	quit_if(fscanf(out, "Shell(pid=%d)1} test\nShell(pid=%d)2} /bin/echo test\ntest\nShell(pid=%d)3} Shell(pid=%d)3} Exiting process %d\n", &pid_tmp, &pid_tmp, &pid_tmp, &pid_tmp, &pid_tmp) != 5);
	quit_if(!feof(out));
	fclose(out);
	return EXIT_SUCCESS;
}

/* P5.5: Test of depth-limited sub */
int test_sub(int argc, char **argv)
{
	char *args[] = { "./shell", NULL };
	FILE *out, *err;
	int pids[4], warned_too_deep;

	/* Run the test */
	run_test("sub\nsub\nsub\nexit\nexit\nexit\n", 1, args);
	/* Check output */
	out = fopen("mp2.out", "r");
	err = fopen("mp2.err", "r");
	/* First, check that the subshells were invoked. */
	fscanf(out, "Shell(pid=%d)1} Shell(pid=%d)1} Shell(pid=%d)1} Shell(pid=%d)2} ", &pids[0], &pids[1], &pids[2], &pids[3]);
	quit_if(!((pids[0] != pids[1]) && (pids[1] != pids[2]) && (pids[0] != pids[2]) && (pids[2] == pids[3])));
	/* Next, check for the "Too deep!" message: */
	warned_too_deep = 0;
	/* Use a while loop because multiple processes write to stderr concurrently. */
	while (!warned_too_deep && !feof(err)) {
		char too_deep[11];
		fgets(too_deep, 11, err);
		if (!strncmp(too_deep, "Too deep!\n", 10))
			warned_too_deep = 1;
	}
	quit_if(!warned_too_deep);
	fclose(out);
	fclose(err);
	return EXIT_SUCCESS;
}

/* P5.6: Test of re-executing previous commands */
int test_last(int argc, char **argv)
{
	char *args[] = { "./shell", NULL };
	FILE *out, *err;
	int pid_tmp;

	/* Run the test */
	run_test("!!\n/bin/echo test\n!!\nexit\n", 1, args);
	/* Check output */
	out = fopen("mp2.out", "r");
	quit_if(fscanf(out, "Shell(pid=%d)1} Shell(pid=%d)1} test\nShell(pid=%d)2} /bin/echo test\ntest\nShell(pid=%d)3} Exiting process %d\n", &pid_tmp, &pid_tmp, &pid_tmp, &pid_tmp, &pid_tmp) != 5);
	quit_if(!feof(out));
	fclose(out);
	return EXIT_SUCCESS;
}

int test_copyright(int argc, char **argv)
{
    char editme[]="Copyright";
    char editme2[]="your-netids-here";
    char buffer[100];
    int found = 1;

    freopen("shell.c","r",stdin);
    while(fgets(buffer,99,stdin)!= NULL)
		{
			if(strstr(buffer, editme)) {
				found = 0;
				if(strstr(buffer,editme2)) found = 1;
				break;
			}
		}

    if(found) printf("Please add your netid(s) to the copyright line.");
    return found;
}

/*
 * Main entry point for MP2 test harness
 */
int run_mp2_tests(int argc, char **argv)
{
	/* Tests can be invoked by matching their name or their suite name 
	   or 'all' */
	testentry_t tests[] = {
		{ "sub",     "mp2", test_sub     },
		{ "rerun",   "mp2", test_rerun   },
		{ "last",    "mp2", test_last    },
		{ "counter", "mp2", test_counter },
		{ "copyright", "mp2", test_copyright },
		{ "path",    "mp2", test_path    } };
	unlink("mp2.in");
	unlink("mp2.out");
	unlink("mp2.err");
	return run_testrunner(argc, argv, tests, sizeof(tests) / sizeof (testentry_t));
}

int main(int argc, char **argv)
{
	/* Entrypoint for the testrunner program */
	if (argc > 1 && !strcmp(argv[1], "-test")) {
		return run_mp2_tests(argc - 1, argv + 1);
	} else {
		return mp2_main(argc, argv);
	}
}
